package com.wolf.cx330.view.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 心电图View
 * <p>
 * 说明
 * 1. X轴的刻度和Y轴的值是动态传入的,请看ECGData;
 * 2. Y轴的刻度是动态变化的,没有写死值,请不要传过分的数值进来;
 * 3. 所有写成final的值 可以抽取成参数[可以尝试改改看看效果变化] 可以用 context.obtainStyledAttributes 将参数写在XML中也可以直接写成GET_SET或者build模式 随意;
 * 4. 非final的值不要动,牵扯到动态计算;
 */
public class ECGView extends View {
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Path path = new Path();
    List<ECGData> ecgDataList = new ArrayList<>();
    List<Float> ecgValList = new ArrayList<>();
    //  yOffset 保证自动Y刻度不会太飘 这个数越大 越不飘
    final int maxYDashOffset = 2;
    final int minYDashOffset = 2;
    //  刻度长度
    final float dashSize = dp2px(4);
    //  坐标系偏移量
    final float offset = dp2px(40);
    //  刻度字的偏移量
    final float textOffsetY = dp2px(4);
    final float textOffsetX = dp2px(10);
    //  拐角弧度
    final float effectSize = dp2px(20);
    //  X 轴个数 Y 轴个数
    final int xNum = 30;
    final int yNum = 10;
    //  字体大小
    final float textSize = dp2px(8);
    final float strokeWidth = dp2px(1);
    //  部分颜色
    final int lineColor = Color.GRAY;
    final int ecgColor = Color.RED;
    //  ********下面的参数请不要动***********
    //  最大值和最小值
    private float maxVal = 0F;
    private float minVal = 0F;
    //  坐标系下X,Y的相关值
    private float minY;
    private float maxX;
    private float minX;
    private float maxY;
    //  用于计算字范围
    Rect rectText = new Rect();
    //  弧度偏移List[每个拐点的Y轴偏移]
    List<Float> cornerEffectOffsetList = new ArrayList<>();

    {
        paint.setPathEffect(new CornerPathEffect(effectSize));
        paint.setTextSize(textSize);
        paint.setStrokeWidth(strokeWidth);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        maxY = h - offset;
        minY = offset;
        maxX = w - offset;
        minX = offset;
    }

    public ECGView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    @SuppressLint("DefaultLocale")
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        toLineMode();
        //  Y轴
        canvas.drawLine(minX, maxY, minX, minY, paint);
        //  Y轴刻度
        for (int i = 0; i <= yNum; i++) {
            float dashY = maxY - ((maxY - minY) / yNum * i);
            canvas.drawLine(minX, dashY, minX + dashSize, dashY, paint);
            //  刻度字
            String text = String.format("%.1f", minVal + (maxVal - minVal) / yNum * i);
            if (i == 0) {
                text = String.format("%.1f", minVal);
            }
            paint.getTextBounds(text, 0, text.length(), rectText);
            canvas.drawText(text, minX - rectText.right - textOffsetY, dashY + (rectText.bottom - rectText.top) / 2F, paint);
        }
        //  X轴
        canvas.drawLine(minX, maxY, maxX, maxY, paint);
        //  X轴刻度
        for (int i = 0; i < xNum; i++) {
            float dashX = minX + ((maxX - minX) / xNum * i);
            canvas.drawLine(dashX, maxY, dashX, maxY - dashSize, paint);
            if (ecgDataList != null && ecgDataList.size() > i) {
                if (i == 0) continue;
                ECGData data = ecgDataList.get(i);
                if (data != null) {
                    //  刻度字
                    String text = data.xVal;
                    paint.getTextBounds(text, 0, text.length(), rectText);
                    canvas.drawText(text, dashX - (rectText.right - rectText.left) / 2F, maxY + rectText.bottom + textOffsetX, paint);
                }
            }
        }
        toEcgModel();
        canvas.drawPath(path, paint);
    }

    /**
     * 添加一个ECGData值且重新计算Path
     *
     * @param data ECGData
     */
    public void addVal(ECGData data) {
        path.reset();
        if (ecgDataList.size() == xNum) {
            ecgDataList.remove(0);
            ecgValList.remove(0);
        }
        ecgDataList.add(data);
        ecgValList.add(data.yVal);
        //
        maxVal = getMaxY(ecgValList);
        minVal = getMinY(ecgValList);

        //  重新组建path
        for (int i = 0; i < ecgDataList.size(); i++) {
            float tempY = ecgDataList.get(i).yVal;
            //  X 轴的值
            float x = (minX + (i * ((maxX - minX) / xNum)));
            //  (tempY - minVal) : (maxVal- minVal) = y :(maxY-minY)
            float maxValScale = (maxVal - minVal);
            if (maxValScale <= 0) {
                maxValScale = maxVal;
            }
            float y = (maxY - ((tempY - minVal) * (maxY - minY)) / (maxValScale));
            //  如果是第一个点 那么移动过去作为起点
            if (i == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
        }
        //  计算拐点偏移
        //  initEffectOffsetList();
        invalidate();
    }


    private void initEffectOffsetList() {
        float x0 = 0;
        float x1 = (maxX - minX) / xNum;
        float x2 = ((maxX - minX) / xNum) *2;

        //  有三个点以上 才可以计算夹角
        if (ecgDataList.size() >= 2) {
            for (int i = 2; i < ecgDataList.size(); i++) {
                //  拿到三个Y坐标
                float y0 = ecgDataList.get(i - 2).yVal;
                float y1 = ecgDataList.get(i - 1).yVal;
                float y2 = ecgDataList.get(i).yVal;
                //  拿到三条边
                float edgeB = getLineLength(x0, y0, x1, y1);
                float edgeC = getLineLength(x1, y1, x2, y2);
                float edgeA = getLineLength(x0, y0, x2, y2);
                //  拿到Cos值
                float cos = getCos(edgeB, edgeC, edgeA);
                //
                System.out.println("【IM】ECGView  initEffectOffsetList: cos = " + cos);
//                cornerEffectOffsetList.add()
            }
        }
    }

    /**
     * 给定两个点的坐标,求长度
     */
    private float getLineLength(float x0, float y0, float x1, float y1) {
        return (float) Math.sqrt(((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1)));
    }

    /**
     * 根据三边获取夹角cos值
     * https://zhidao.baidu.com/question/549634951.html
     *
     * @param a 对边
     * @param b 临边1
     * @param c 临边2
     * @return cos
     */
    private float getCos(float b, float c, float a) {
        return (b * b + c * c - a * a) / (2 * b * c);
    }

    private int getMaxY(List<Float> list) {
        List<Float> tempList = new ArrayList<>(list);
        Collections.sort(tempList);
        return (int) Math.ceil(tempList.get(tempList.size() - 1)) + maxYDashOffset;
    }

    private int getMinY(List<Float> list) {
        List<Float> tempList = new ArrayList<>(list);
        Collections.sort(tempList);
        int ret = (int) Math.floor(tempList.get(0));
        if (ret >= minYDashOffset) {
            return ret - minYDashOffset;
        } else {
            return 0;
        }
    }

    /**
     * dp2px
     *
     * @param dp dp
     * @return px
     */
    float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }

    private void toLineMode() {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(lineColor);
    }

    private void toEcgModel() {
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(ecgColor);
    }

    public static class ECGData {
        float yVal;
        String xVal;

        public ECGData(float yVal, String xVal) {
            this.yVal = yVal;
            this.xVal = xVal;
        }
    }
}
